home *** CD-ROM | disk | FTP | other *** search
- /* Lisp object printing and output streams.
- Copyright (C) 1985, 1986, 1988, 1992, 1993, 1994
- Free Software Foundation, Inc.
- Copyright (C) 1994, 1995 Amdahl Corporation.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not synched with FSF. */
-
- /* This file has been Mule-ized. */
-
- /* Seriously hacked on by Ben Wing for Mule. */
-
- #include <config.h>
- #include "lisp.h"
-
- #ifndef standalone
- #include "buffer.h"
- #include "bytecode.h"
- #include "extents.h"
- #include "frame.h"
- #include "emacsfns.h"
- #include "insdel.h"
- #include "lstream.h"
-
- #endif /* not standalone */
-
- Lisp_Object Vstandard_output, Qstandard_output;
-
- /* The subroutine object for external-debugging-output is kept here
- for the convenience of the debugger. */
- Lisp_Object Qexternal_debugging_output;
- Lisp_Object Qalternate_debugging_output;
-
- /* Avoid actual stack overflow in print. */
- static int print_depth;
-
- /* Maximum length of list or vector to print in full; noninteger means
- effectively infinity */
-
- Lisp_Object Vprint_length;
- Lisp_Object Qprint_length;
-
- /* Maximum length of string to print in full; noninteger means
- effectively infinity */
-
- Lisp_Object Vprint_string_length;
- Lisp_Object Qprint_string_length;
-
- /* Maximum depth of list to print in full; noninteger means
- effectively infinity. */
-
- Lisp_Object Vprint_level;
-
- /* Label to use when making echo-area messages. */
-
- Lisp_Object Vprint_message_label;
-
- /* Nonzero means print newlines in strings as \n. */
-
- int print_escape_newlines;
- int print_readably;
- int print_gensym;
-
- Lisp_Object Qprint_escape_newlines;
- Lisp_Object Qprint_readably;
-
- /* Force immediate output of all printed data. Used for debugging. */
- int print_unbuffered;
-
- FILE *termscript; /* Stdio stream being used for copy of all output. */
-
-
-
- int stdout_needs_newline;
-
- /* Write a string (in internal format) to stdio stream STREAM. */
-
- void
- write_string_to_stdio_stream (FILE *stream, CONST Bufbyte *str,
- Bytecount offset, Bytecount len)
- {
- int extlen;
- char *extptr = charptr_to_external (str + offset, len, &extlen);
- fwrite (extptr, 1, extlen, stream);
- if (stream == stdout || stream == stderr)
- {
- if (termscript)
- {
- fwrite (extptr, 1, extlen, termscript);
- fflush (termscript);
- }
- stdout_needs_newline = (extptr[extlen - 1] != '\n');
- }
- }
-
- /* Write a string to the output location specified in FUNCTION.
- Arguments NONRELOC, RELOC, OFFSET, and LEN are as in
- buffer_insert_string_1() in insdel.c. */
-
- static void
- output_string (Lisp_Object function, CONST Bufbyte *nonreloc,
- Lisp_Object reloc, Bytecount offset, Bytecount len)
- {
- /* This function can GC */
- Charcount ccoff, cclen;
- /* We change the value of nonreloc (fetching it from reloc as
- necessary), but we don't want to pass this changed value on to
- other functions that take both a nonreloc and a reloc, or things
- may get confused and an assertion failure in
- fixup_internal_substring() may get triggered. */
- CONST Bufbyte *newnonreloc = nonreloc;
- struct gcpro gcpro1, gcpro2;
-
- /* Emacs won't print whilst GCing, but an external debugger might */
- if (gc_in_progress) return;
-
- /* Perhaps not necessary but probably safer. */
- GCPRO2 (function, reloc);
-
- fixup_internal_substring (newnonreloc, reloc, offset, &len);
-
- if (STRINGP (reloc))
- newnonreloc = string_data (XSTRING (reloc));
-
- ccoff = bytecount_to_charcount (newnonreloc, offset);
- cclen = bytecount_to_charcount (newnonreloc + offset, len);
-
- if (LSTREAMP (function))
- {
- /* Lstream_write() could easily cause GC inside of it, if the
- stream is a print-stream. (It will call output_string()
- recursively.) This is probably the fastest way to fix this
- problem. (alloca() is very fast on machines that have it
- built-in, and you avoid some nasty problems with recursion
- that could result from using a static buffer somewhere.)
-
- The other possibility is to inhibit GC, but that of course
- would require an unwind-protect, which is usually a lot
- slower than the small amount of memcpy()ing that happens
- here. */
- if (STRINGP (reloc))
- {
- Bufbyte *copied = (Bufbyte *) alloca (len);
- memcpy (copied, newnonreloc + offset, len);
- Lstream_write (XLSTREAM (function), copied, len);
- }
- else
- Lstream_write (XLSTREAM (function), newnonreloc + offset, len);
-
- if (print_unbuffered)
- Lstream_flush (XLSTREAM (function));
- }
-
- #ifndef standalone
- else if (BUFFERP (function))
- {
- CHECK_LIVE_BUFFER (function, 0);
- buffer_insert_string (XBUFFER (function), nonreloc, reloc, offset, len);
- }
- else if (MARKERP (function))
- {
- /* marker_position will err if marker doesn't point anywhere */
- Bufpos spoint = marker_position (function);
-
- buffer_insert_string_1 (XBUFFER (Fmarker_buffer (function)),
- spoint, nonreloc, reloc, offset, len,
- 0);
- Fset_marker (function, make_number (spoint + cclen), Qnil);
- }
- else if (FRAMEP (function))
- {
- struct frame *f = XFRAME (function);
- if (!EQ (Vprint_message_label, echo_area_status (f)))
- clear_echo_area_from_print (f, Qnil, 1);
- echo_area_append (f, nonreloc, reloc, offset, len, Vprint_message_label);
- }
- #endif /* not standalone */
- else if (EQ (function, Qt) || EQ (function, Qnil))
- {
- write_string_to_stdio_stream (stdout, newnonreloc, offset, len);
- }
- else
- {
- Charcount iii;
-
- for (iii = ccoff; iii < cclen + ccoff; iii++)
- {
- call1 (function,
- make_number (charptr_char (newnonreloc, iii)));
- if (STRINGP (reloc))
- newnonreloc = string_data (XSTRING (reloc));
- }
- }
-
- UNGCPRO;
- }
-
- struct print_stream
- {
- FILE *file;
- Lisp_Object fun;
- };
-
- #define get_print_stream(stream) \
- ((struct print_stream *) Lstream_data (stream))
-
- static int print_stream_writer (Lstream *stream, CONST unsigned char *data,
- int size);
- static Lisp_Object print_stream_marker (Lisp_Object obj,
- void (*markobj) (Lisp_Object));
-
- DEFINE_LSTREAM_IMPLEMENTATION ("print", lstream_print, 0,
- print_stream_writer, 0, 0, print_stream_marker,
- sizeof (struct print_stream));
-
- static Lstream *
- make_print_stream (FILE *file, Lisp_Object fun)
- {
- Lstream *str = Lstream_new (lstream_print);
- struct print_stream *ps = get_print_stream (str);
-
- ps->file = file;
- ps->fun = fun;
- return str;
- }
-
- /* #### This isn't being used anywhere at the moment. Is it supposed
- to be? */
- #if 0
- static void
- reset_print_stream (Lstream *str, FILE *file, Lisp_Object fun)
- {
- struct print_stream *ps = get_print_stream (str);
-
- Lstream_reopen (str);
- ps->file = file;
- ps->fun = fun;
- }
- #endif
-
- static Lisp_Object
- print_stream_marker (Lisp_Object obj, void (*markobj) (Lisp_Object))
- {
- return get_print_stream (XLSTREAM (obj))->fun;
- }
-
- static int
- print_stream_writer (Lstream *stream, CONST unsigned char *data, int size)
- {
- struct print_stream *ps = get_print_stream (stream);
- if (ps->file)
- {
- write_string_to_stdio_stream (ps->file, data, 0, size);
- /* Make sure it really gets written now. */
- if (print_unbuffered)
- fflush (ps->file);
- }
- else
- output_string (ps->fun, data, Qnil, 0, size);
- return size;
- }
-
-
- static Lisp_Object
- canonicalise_printcharfun (Lisp_Object printcharfun)
- {
- if (NILP (printcharfun))
- printcharfun = Vstandard_output;
-
- if (EQ (printcharfun, Qt) || NILP (printcharfun))
- {
- #ifndef standalone
- printcharfun = Fselected_frame (Qnil); /* print to minibuffer */
- #endif
- }
- return (printcharfun);
- }
-
-
- static Lisp_Object
- print_prepare (Lisp_Object printcharfun)
- {
- Lisp_Object xstream = Qnil;
- Lstream *s;
- FILE *stdio_stream = 0;
-
- /* Emacs won't print whilst GCing, but an external debugger might */
- if (gc_in_progress)
- return (Qnil);
-
- printcharfun = canonicalise_printcharfun (printcharfun);
- if (EQ (printcharfun, Qnil))
- {
- stdio_stream = stdout;
- }
- #if 0 /* Don't bother */
- else if (SUBRP (indirect_function (printcharfun, 0))
- && (XSUBR (indirect_function (printcharfun, 0))
- == Sexternal_debugging_output))
- {
- stdio_stream = stderr;
- }
- #endif
-
- s = make_print_stream (stdio_stream, printcharfun);
- XSETLSTREAM (xstream, s);
- return (xstream);
- }
-
- static void
- print_finish (Lisp_Object stream)
- {
- /* Emacs won't print whilst GCing, but an external debugger might */
- if (gc_in_progress)
- return;
-
- Lstream_close (XLSTREAM (stream));
- }
-
- #if 1 /* Prefer space over "speed" */
- #define write_char_internal(string_of_length_1, stream) \
- write_string_1 ((Bufbyte *) (string_of_length_1), 1, (stream))
- #else
- #define write_char_internal(string_of_length_1, stream) \
- output_string ((stream), (Bufbyte *) (string_of_length_1), Qnil, 0, 1)
- #endif
-
- /* NOTE: Do not call this with the data of a Lisp_String,
- * as printcharfun might cause a GC, which might cause
- * the string's data to be relocated.
- * Use print_object_internal (string, printcharfun, 0)
- * to princ a Lisp_String
- * Note: "stream" should be the result of "canonicalise_printcharfun"
- * (ie Qnil means stdout, not Vstandard_output, etc)
- */
- void
- write_string_1 (CONST Bufbyte *str, Bytecount size, Lisp_Object stream)
- {
- /* This function can GC */
- assert (size >= 0);
- output_string (stream, str, Qnil, 0, size);
- }
-
- void
- write_c_string (CONST char *str, Lisp_Object stream)
- {
- /* This function can GC */
- write_string_1 ((Bufbyte *) str, strlen (str), stream);
- }
-
-
- DEFUN ("write-char", Fwrite_char, Swrite_char, 1, 2, 0,
- "Output character CH to stream STREAM.\n\
- STREAM defaults to the value of `standard-output' (which see).")
- (ch, stream)
- Lisp_Object ch, stream;
- {
- /* This function can GC */
- Bufbyte str[MAX_EMCHAR_LEN];
- Bytecount len;
-
- CHECK_COERCE_CHAR (ch, 0);
- len = emchar_to_charptr (XINT (ch), str);
- output_string (canonicalise_printcharfun (stream), str, Qnil, 0, len);
- return ch;
- }
-
- #ifndef standalone
-
- void
- temp_output_buffer_setup (CONST char *bufname)
- {
- /* This function can GC */
- struct buffer *old = current_buffer;
- Lisp_Object buf;
-
- #ifdef I18N3
- /* #### This function should accept a Lisp_Object instead of a char *,
- so that proper translation on the buffer name can occur. */
- #endif
-
- Fset_buffer (Fget_buffer_create (build_string (bufname)));
-
- current_buffer->read_only = Qnil;
- Ferase_buffer (Fcurrent_buffer ());
-
- XSETBUFFER (buf, current_buffer);
- specbind (Qstandard_output, buf);
-
- set_buffer_internal (old);
- }
-
- Lisp_Object
- internal_with_output_to_temp_buffer (CONST char *bufname,
- Lisp_Object (*function) (Lisp_Object arg),
- Lisp_Object arg,
- Lisp_Object same_frame)
- {
- int speccount = specpdl_depth ();
- struct gcpro gcpro1, gcpro2, gcpro3;
- Lisp_Object buf = Qnil;
-
- GCPRO3 (buf, arg, same_frame);
-
- temp_output_buffer_setup (GETTEXT (bufname));
- buf = Vstandard_output;
-
- arg = (*function) (arg);
-
- temp_output_buffer_show (buf, same_frame);
- UNGCPRO;
-
- return unbind_to (speccount, arg);
- }
-
- DEFUN ("with-output-to-temp-buffer", Fwith_output_to_temp_buffer, Swith_output_to_temp_buffer,
- 1, UNEVALLED, 0,
- "Bind `standard-output' to buffer BUFNAME, eval BODY, then show that buffer.\n\
- The buffer is cleared out initially, and marked as unmodified when done.\n\
- All output done by BODY is inserted in that buffer by default.\n\
- The buffer is displayed in another window, but not selected.\n\
- The value of the last form in BODY is returned.\n\
- If BODY does not finish normally, the buffer BUFNAME is not displayed.\n\n\
- If variable `temp-buffer-show-function' is non-nil, call it at the end\n\
- to get the buffer displayed. It gets one argument, the buffer to display.")
- (args)
- Lisp_Object args;
- {
- /* This function can GC */
- struct gcpro gcpro1;
- Lisp_Object name;
- int speccount = specpdl_depth ();
- Lisp_Object buf, val;
-
- #ifdef I18N3
- /* #### should set the buffer to be translating. See print_internal(). */
- #endif
-
- GCPRO1 (args);
- name = Feval (Fcar (args));
- UNGCPRO;
-
- CHECK_STRING (name, 0);
- temp_output_buffer_setup ((char *) string_data (XSTRING (name)));
- buf = Vstandard_output;
-
- val = Fprogn (Fcdr (args));
-
- temp_output_buffer_show (buf, Qnil);
-
- return unbind_to (speccount, val);
- }
- #endif /* not standalone */
-
- DEFUN ("terpri", Fterpri, Sterpri, 0, 1, 0,
- "Output a newline to STREAM.\n\
- If STREAM is omitted or nil, the value of `standard-output' is used.")
- (stream)
- Lisp_Object stream;
- {
- /* This function can GC */
- Bufbyte str[1];
- str[0] = '\n';
- output_string (canonicalise_printcharfun (stream), str, Qnil, 0, 1);
- return Qt;
- }
-
- DEFUN ("prin1", Fprin1, Sprin1, 1, 2, 0,
- "Output the printed representation of OBJECT, any Lisp object.\n\
- Quoting characters are printed when needed to make output that `read'\n\
- can handle, whenever this is possible.\n\
- Output stream is STREAM, or value of `standard-output' (which see).")
- (object, stream)
- Lisp_Object object, stream;
- {
- /* This function can GC */
- Lisp_Object the_stream = Qnil;
- struct gcpro gcpro1, gcpro2, gcpro3;
-
- GCPRO3 (object, stream, the_stream);
- print_depth = 0;
- the_stream = print_prepare (stream);
- print_internal (object, the_stream, 1);
- print_finish (the_stream);
- UNGCPRO;
- return object;
- }
-
- /* a buffer which is used to hold output being built by prin1-to-string */
- Lisp_Object Vprin1_to_string_buffer;
-
- DEFUN ("prin1-to-string", Fprin1_to_string, Sprin1_to_string, 1, 2, 0,
- "Return a string containing the printed representation of OBJECT,\n\
- any Lisp object. Quoting characters are used when needed to make output\n\
- that `read' can handle, whenever this is possible, unless the optional\n\
- second argument NOESCAPE is non-nil.")
- (object, noescape)
- Lisp_Object object, noescape;
- {
- /* This function can GC */
- Lisp_Object old = Fcurrent_buffer ();
- struct buffer *out = XBUFFER (Vprin1_to_string_buffer);
- Lisp_Object stream = Qnil;
- struct gcpro gcpro1, gcpro2, gcpro3;
-
- GCPRO3 (object, old, stream);
- stream = print_prepare (Vprin1_to_string_buffer);
- set_buffer_internal (out);
- Ferase_buffer (Fcurrent_buffer ());
- print_depth = 0;
- print_internal (object, stream, NILP (noescape));
- print_finish (stream);
- stream = Qnil; /* No GC surprises! */
- object = make_string_from_buffer (out,
- BUF_BEG (out),
- BUF_Z (out) - 1);
- Ferase_buffer (Fcurrent_buffer ());
- Fset_buffer (old);
- UNGCPRO;
- return (object);
- }
-
- DEFUN ("princ", Fprinc, Sprinc, 1, 2, 0,
- "Output the printed representation of OBJECT, any Lisp object.\n\
- No quoting characters are used; no delimiters are printed around\n\
- the contents of strings.\n\
- Output stream is STREAM, or value of standard-output (which see).")
- (obj, stream)
- Lisp_Object obj, stream;
- {
- /* This function can GC */
- Lisp_Object the_stream = Qnil;
- struct gcpro gcpro1, gcpro2, gcpro3;
-
- GCPRO3 (obj, stream, the_stream);
- the_stream = print_prepare (stream);
- print_depth = 0;
- print_internal (obj, the_stream, 0);
- print_finish (the_stream);
- UNGCPRO;
- return (obj);
- }
-
- DEFUN ("print", Fprint, Sprint, 1, 2, 0,
- "Output the printed representation of OBJECT, with newlines around it.\n\
- Quoting characters are printed when needed to make output that `read'\n\
- can handle, whenever this is possible.\n\
- Output stream is STREAM, or value of `standard-output' (which see).")
- (obj, stream)
- Lisp_Object obj, stream;
- {
- /* This function can GC */
- Lisp_Object the_stream = Qnil;
- struct gcpro gcpro1, gcpro2, gcpro3;
-
- GCPRO3 (obj, stream, the_stream);
- the_stream = print_prepare (stream);
- print_depth = 0;
- write_char_internal ("\n", the_stream);
- print_internal (obj, the_stream, 1);
- write_char_internal ("\n", the_stream);
- print_finish (the_stream);
- UNGCPRO;
- return obj;
- }
-
- #ifdef LISP_FLOAT_TYPE
-
- Lisp_Object Vfloat_output_format;
- Lisp_Object Qfloat_output_format;
-
- void
- float_to_string (char *buf, double data)
- /*
- * This buffer should be at least as large as the max string size of the
- * largest float, printed in the biggest notation. This is undoubtably
- * 20d float_output_format, with the negative of the C-constant "HUGE"
- * from <math.h>.
- *
- * On the vax the worst case is -1e38 in 20d format which takes 61 bytes.
- *
- * I assume that IEEE-754 format numbers can take 329 bytes for the worst
- * case of -1e307 in 20d float_output_format. What is one to do (short of
- * re-writing _doprnt to be more sane)?
- * -wsr
- */
- {
- Bufbyte *cp, c;
- int width;
-
- if (NILP (Vfloat_output_format)
- || !STRINGP (Vfloat_output_format))
- lose:
- sprintf (buf, "%.16g", data);
- else /* oink oink */
- {
- /* Check that the spec we have is fully valid.
- This means not only valid for printf,
- but meant for floats, and reasonable. */
- cp = string_data (XSTRING (Vfloat_output_format));
-
- if (cp[0] != '%')
- goto lose;
- if (cp[1] != '.')
- goto lose;
-
- cp += 2;
- for (width = 0; (c = *cp, isdigit (c)); cp++)
- {
- width *= 10;
- width += c - '0';
- }
-
- if (*cp != 'e' && *cp != 'f' && *cp != 'g' && *cp != 'E' && *cp != 'G')
- goto lose;
-
- if (width < (int) (*cp != 'e' && *cp != 'E') || width > DBL_DIG)
- goto lose;
-
- if (cp[1] != 0)
- goto lose;
-
- sprintf (buf, (char *) string_data (XSTRING (Vfloat_output_format)),
- data);
- }
-
- /* added by jwz: don't allow "1.0" to print as "1"; that destroys
- the read-equivalence of lisp objects. (* x 1) and (* x 1.0) do
- not do the same thing, so it's important that the printed
- representation of that form not be corrupted by the printer.
- */
- {
- Bufbyte *s = (Bufbyte *) buf; /* don't use signed chars here!
- isdigit() can't hack them! */
- if (*s == '-') s++;
- for (; *s; s++)
- /* if there's a non-digit, then there is a decimal point, or
- it's in exponential notation, both of which are ok. */
- if (!isdigit (*s))
- goto DONE_LABEL;
- /* otherwise, we need to hack it. */
- *s++ = '.';
- *s++ = '0';
- *s = 0;
- }
- DONE_LABEL:
-
- /* Some machines print "0.4" as ".4". I don't like that. */
- if (buf [0] == '.' || (buf [0] == '-' && buf [1] == '.'))
- {
- int i;
- for (i = strlen (buf) + 1; i >= 0; i--)
- buf [i+1] = buf [i];
- buf [(buf [0] == '-' ? 1 : 0)] = '0';
- }
- }
- #endif /* LISP_FLOAT_TYPE */
-
- static void
- print_vector_internal (CONST char *start, CONST char *end,
- Lisp_Object obj,
- Lisp_Object printcharfun, int escapeflag)
- {
- /* This function can GC */
- int i;
- int len = vector_length (XVECTOR (obj));
- int last = len;
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (obj, printcharfun);
-
- if (INTP (Vprint_length))
- {
- int max = XINT (Vprint_length);
- if (max < len) last = max;
- }
-
- write_c_string (start, printcharfun);
- for (i = 0; i < last; i++)
- {
- Lisp_Object elt = vector_data (XVECTOR (obj))[i];
- if (i != 0) write_char_internal (" ", printcharfun);
- print_internal (elt, printcharfun, escapeflag);
- }
- UNGCPRO;
- if (last != len)
- write_c_string (" ...", printcharfun);
- write_c_string (end, printcharfun);
- }
-
- static void
- default_object_printer (Lisp_Object obj, Lisp_Object printcharfun,
- int escapeflag)
- {
- struct lcrecord_header *header =
- (struct lcrecord_header *) XPNTR (obj);
- char buf[200];
-
- if (print_readably)
- error ("printing unreadable object #<%s 0x%x>",
- header->lheader.implementation->name, header->uid);
-
- sprintf (buf, "#<%s 0x%x>", header->lheader.implementation->name,
- header->uid);
- write_c_string (buf, printcharfun);
- }
-
- void
- print_internal (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
- {
- /* This function can GC */
- char buf[256];
-
- QUIT;
-
- /* Emacs won't print whilst GCing, but an external debugger might */
- if (gc_in_progress) return;
-
- #ifdef I18N3
- /* #### Both input and output streams should have a flag associated
- with them indicating whether output to that stream, or strings
- read from the stream, get translated using Fgettext(). Such a
- stream is called a "translating stream". For the minibuffer and
- external-debugging-output this is always true on output, and
- with-output-to-temp-buffer sets the flag to true for the buffer
- it creates. This flag should also be user-settable. Perhaps it
- should be split up into two flags, one for input and one for
- output. */
- #endif
-
- print_depth++;
-
- if (print_depth > 200)
- error ("Apparently circular structure being printed");
-
- switch (XTYPE (obj))
- {
- case Lisp_Int:
- {
- sprintf (buf, "%d", XINT (obj));
- write_c_string (buf, printcharfun);
- break;
- }
-
- case Lisp_String:
- {
- Bytecount size = string_length (XSTRING (obj));
- struct gcpro gcpro1, gcpro2;
- int max = size;
- GCPRO2 (obj, printcharfun);
-
- if (INTP (Vprint_string_length) &&
- XINT (Vprint_string_length) < max)
- max = XINT (Vprint_string_length);
- if (max < 0)
- max = 0;
-
- if (!escapeflag)
- {
- /* This deals with GC-relocation */
- output_string (printcharfun, 0, obj, 0, max);
- if (max < size)
- write_c_string (" ...", printcharfun);
- }
- else
- {
- Bytecount i;
- struct Lisp_String *s = XSTRING (obj);
- Bytecount last = 0;
-
- write_char_internal ("\"", printcharfun);
- for (i = 0; i < max; i++)
- {
- Bufbyte ch = string_byte (s, i);
- if (ch == '\"' || ch == '\\'
- || (ch == '\n' && print_escape_newlines))
- {
- if (i > last)
- {
- output_string (printcharfun, 0, obj, last,
- i - last);
- }
- if (ch == '\n')
- {
- write_c_string ("\\n", printcharfun);
- }
- else
- {
- write_char_internal ("\\", printcharfun);
- /* This is correct for Mule because the
- character is either \ or " */
- write_char_internal ((char *) (string_data (s) + i),
- printcharfun);
- }
- last = i + 1;
- }
- }
- if (max > last)
- {
- output_string (printcharfun, 0, obj, last,
- max - last);
- }
- if (max < size)
- write_c_string (" ...", printcharfun);
- write_char_internal ("\"", printcharfun);
- }
- UNGCPRO;
- break;
- }
-
- case Lisp_Cons:
- {
- struct gcpro gcpro1, gcpro2;
-
- /* If deeper than spec'd depth, print placeholder. */
- if (INTP (Vprint_level)
- && print_depth > XINT (Vprint_level))
- {
- write_c_string ("...", printcharfun);
- break;
- }
-
- /* If print_readably is on, print (quote -foo-) as '-foo-
- (Yeah, this should really be what print-pretty does, but we
- don't have the rest of a pretty printer, and this actually
- has non-negligible impact on size/speed of .elc files.)
- */
- if (print_readably &&
- EQ (XCAR (obj), Qquote) &&
- CONSP (XCDR (obj)) &&
- NILP (XCDR (XCDR (obj))))
- {
- obj = XCAR (XCDR (obj));
- GCPRO2 (obj, printcharfun);
- write_char_internal ("'", printcharfun);
- UNGCPRO;
- print_internal (obj, printcharfun, escapeflag);
- break;
- }
-
- GCPRO2 (obj, printcharfun);
- write_char_internal ("(", printcharfun);
- {
- int i = 0;
- int max = 0;
-
- if (INTP (Vprint_length))
- max = XINT (Vprint_length);
- while (CONSP (obj))
- {
- if (i++)
- write_char_internal (" ", printcharfun);
- if (max && i > max)
- {
- write_c_string ("...", printcharfun);
- break;
- }
- print_internal (Fcar (obj), printcharfun,
- escapeflag);
- obj = Fcdr (obj);
- }
- }
- if (!NILP (obj) && !CONSP (obj))
- {
- write_c_string (" . ", printcharfun);
- print_internal (obj, printcharfun, escapeflag);
- }
- UNGCPRO;
- write_char_internal (")", printcharfun);
- break;
- }
-
- #ifndef LRECORD_VECTOR
- case Lisp_Vector:
- {
- /* If deeper than spec'd depth, print placeholder. */
- if (INTP (Vprint_level)
- && print_depth > XINT (Vprint_level))
- {
- write_c_string ("...", printcharfun);
- break;
- }
-
- /* God intended that this be #(...), you know. */
- print_vector_internal ("[", "]", obj, printcharfun, escapeflag);
- break;
- }
- #endif /* !LRECORD_VECTOR */
-
- #ifndef LRECORD_SYMBOL
- case Lisp_Symbol:
- {
- print_symbol (obj, printcharfun, escapeflag);
- break;
- }
- #endif /* !LRECORD_SYMBOL */
-
- case Lisp_Record:
- {
- struct lrecord_header *lheader = XRECORD_LHEADER (obj);
- struct gcpro gcpro1, gcpro2;
-
- GCPRO2 (obj, printcharfun);
- if (lheader->implementation->printer)
- ((lheader->implementation->printer)
- (obj, printcharfun, escapeflag));
- else
- default_object_printer (obj, printcharfun, escapeflag);
- UNGCPRO;
- break;
- }
-
- default:
- {
- /* We're in trouble if this happens!
- Probably should just abort () */
- if (print_readably)
- error ("printing illegal data type #o%03o",
- (int) XTYPE (obj));
- write_c_string ("#<EMACS BUG: ILLEGAL DATATYPE ",
- printcharfun);
- sprintf (buf, "(#o%3o)", (int) XTYPE (obj));
- write_c_string (buf, printcharfun);
- write_c_string
- (" Save your buffers immediately and please report this bug>",
- printcharfun);
- break;
- }
- }
-
- print_depth--;
- }
-
- static void
- print_bytecode_internal (CONST char *start, CONST char *end,
- Lisp_Object obj,
- Lisp_Object printcharfun, int escapeflag)
- {
- /* This function can GC */
- struct Lisp_Bytecode *b = XBYTECODE (obj); /* GC doesn't relocate */
- int docp = b->flags.documentationp;
- int intp = b->flags.interactivep;
- struct gcpro gcpro1, gcpro2;
- char buf[100];
- GCPRO2 (obj, printcharfun);
-
- write_c_string (start, printcharfun);
- /* COMPILED_ARGLIST = 0 */
- print_internal (b->arglist, printcharfun, escapeflag);
- /* COMPILED_BYTECODE = 1 */
- write_char_internal (" ", printcharfun);
- print_internal (b->bytecodes, printcharfun, escapeflag);
- /* COMPILED_CONSTANTS = 2 */
- write_char_internal (" ", printcharfun);
- print_internal (b->constants, printcharfun, escapeflag);
- /* COMPILED_STACK_DEPTH = 3 */
- sprintf (buf, " %d", b->maxdepth);
- write_c_string (buf, printcharfun);
- /* COMPILED_DOC_STRING = 4 */
- if (docp || intp)
- {
- write_char_internal (" ", printcharfun);
- print_internal (bytecode_documentation (b), printcharfun,
- escapeflag);
- }
- /* COMPILED_INTERACTIVE = 5 */
- if (intp)
- {
- write_char_internal (" ", printcharfun);
- print_internal (bytecode_interactive (b), printcharfun,
- escapeflag);
- }
- UNGCPRO;
- write_c_string (end, printcharfun);
- }
-
- void
- print_bytecode (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
- {
- /* This function can GC */
- print_bytecode_internal (((print_readably) ? "#[" : "#<byte-code "),
- ((print_readably) ? "]" : ">"),
- obj, printcharfun, escapeflag);
- }
-
- #ifdef LISP_FLOAT_TYPE
- void
- print_float (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
- {
- char pigbuf[350]; /* see comments in float_to_string */
-
- float_to_string (pigbuf, float_data (XFLOAT (obj)));
- write_c_string (pigbuf, printcharfun);
- }
- #endif /* LISP_FLOAT_TYPE */
-
- void
- print_symbol (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
- {
- /* This function can GC */
- /* #### Bug!! (intern "") isn't printed in some distinguished way */
- /* #### (the reader also loses on it) */
- struct Lisp_String *name = XSYMBOL (obj)->name;
- Bytecount size = string_length (name);
- struct gcpro gcpro1, gcpro2;
-
- if (!escapeflag)
- {
- /* This deals with GC-relocation */
- Lisp_Object nameobj;
- XSETSTRING (nameobj, name);
- output_string (printcharfun, 0, nameobj, 0, size);
- return;
- }
- GCPRO2 (obj, printcharfun);
-
- if (print_gensym)
- {
- Lisp_Object tem = oblookup (Vobarray, string_data (name), size);
- if (!EQ (tem, obj))
- /* (read) would return a new symbol with the same name.
- This isn't quite correct, because that symbol might not
- really be uninterned (it might be interned in some other
- obarray) but there's no way to win in that case without
- implementing a real package system.
- */
- write_c_string ("#:", printcharfun);
- }
-
- /* Does it look like an integer or a float? */
- {
- Bufbyte *data = string_data (name);
- Bytecount confusing = 0;
-
- if (size == 0)
- goto not_yet_confused; /* Really confusing */
- else if (isdigit (data[0]))
- confusing = 0;
- else if (size == 1)
- goto not_yet_confused;
- else if (data[0] == '-' || data[0] == '+')
- confusing = 1;
- else
- goto not_yet_confused;
-
- for (; confusing < size; confusing++)
- {
- if (!isdigit (data[confusing]))
- {
- confusing = 0;
- break;
- }
- }
- not_yet_confused:
-
- #ifdef LISP_FLOAT_TYPE
- if (!confusing)
- confusing = isfloat_string ((char *) data);
- #endif
- if (confusing)
- write_char_internal ("\\", printcharfun);
- }
-
- {
- Lisp_Object nameobj;
- Bytecount i;
- Bytecount last = 0;
-
- XSETSTRING (nameobj, name);
- for (i = 0; i < size; i++)
- {
- Bufbyte c = string_byte (name, i);
-
- if (c == '\"' || c == '\\' || c == '\'' || c == ';' || c == '#' ||
- c == '(' || c == ')' || c == ',' || c =='.' || c == '`' ||
- c == '[' || c == ']' || c == '?' || c <= 040)
- {
- if (i > last)
- {
- output_string (printcharfun, 0, nameobj, last,
- i - last);
- }
- write_char_internal ("\\", printcharfun);
- last = i;
- }
- }
- output_string (printcharfun, 0, nameobj, last, size - last);
- }
- UNGCPRO;
- }
-
-
- int alternate_do_pointer;
- char alternate_do_string[5000];
-
- DEFUN ("alternate-debugging-output", Falternate_debugging_output,
- Salternate_debugging_output, 1, 1, 0,
- "Append CHARACTER to the array `alternate_do_string'.\n\
- This can be used in place of `external-debugging-output' as a function\n\
- to be passed to `print'. Before calling `print', set `alternate_do_pointer'\n\
- to 0.\n")
- (character)
- Lisp_Object character;
- {
- Bufbyte str[MAX_EMCHAR_LEN];
- Bytecount len;
- int extlen;
- char *extptr;
-
- CHECK_COERCE_CHAR (character, 0);
- len = emchar_to_charptr (XINT (character), str);
- extptr = charptr_to_external (str, len, &extlen);
- memcpy (alternate_do_string + alternate_do_pointer, extptr, extlen);
- alternate_do_pointer += extlen;
- alternate_do_string[alternate_do_pointer] = 0;
- return character;
- }
-
- DEFUN ("external-debugging-output", Fexternal_debugging_output,
- Sexternal_debugging_output, 1, 2, 0,
- "Write CHAR-OR-STRING to stderr or stdout.\n\
- If optional arg STDOUT-P is non-nil, write to stdout; otherwise, write\n\
- to stderr. You can use this function to write directly to the terminal.\n\
- This function can be used as the STREAM argument of Fprint() or the like.\n\
- \n\
- If you have opened a termscript file (using `open-termscript'), then\n\
- the output also will be logged to this file.")
- (char_or_string, stdout_p)
- Lisp_Object char_or_string, stdout_p;
- {
- if (STRINGP (char_or_string))
- write_string_to_stdio_stream (!NILP (stdout_p) ? stdout : stderr,
- string_data (XSTRING (char_or_string)),
- 0, string_length (XSTRING (char_or_string)));
- else
- {
- Bufbyte str[MAX_EMCHAR_LEN];
- Bytecount len;
-
- CHECK_COERCE_CHAR (char_or_string, 0);
- len = emchar_to_charptr (XINT (char_or_string), str);
- write_string_to_stdio_stream (!NILP (stdout_p) ? stdout : stderr,
- str, 0, len);
- }
-
- return char_or_string;
- }
-
- DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
- 1, 1, "FOpen termscript file: ",
- "Start writing all terminal output to FILE as well as the terminal.\n\
- FILE = nil means just close any termscript file currently open.")
- (file)
- Lisp_Object file;
- {
- /* This function can GC */
- if (termscript != 0)
- fclose (termscript);
- termscript = 0;
-
- if (! NILP (file))
- {
- file = Fexpand_file_name (file, Qnil);
- termscript = fopen ((char *) string_data (XSTRING (file)), "w");
- if (termscript == 0)
- report_file_error ("Opening termscript", Fcons (file, Qnil));
- }
- return Qnil;
- }
-
- #if 1
- /* Debugging kludge -- unbuffered */
- static int debug_print_length = 50;
- static int debug_print_level = 15;
- Lisp_Object debug_temp;
- void debug_print (Lisp_Object debug_print_obj);
- void
- debug_print (Lisp_Object debug_print_obj)
- {
- /* This function can GC */
- int old_print_readably = print_readably;
- int old_print_depth = print_depth;
- Lisp_Object old_print_length = Vprint_length;
- Lisp_Object old_print_level = Vprint_level;
- Lisp_Object old_inhibit_quit = Vinhibit_quit;
- struct gcpro gcpro1, gcpro2, gcpro3;
- GCPRO3 (old_print_level, old_print_length, old_inhibit_quit);
-
- if (gc_in_progress)
- stderr_out ("** gc-in-progress! Bad idea to print anything! **\n");
-
- print_depth = 0;
- print_readably = 0;
- print_unbuffered++;
- /* Could use unwind-protect, but why bother? */
- if (debug_print_length > 0)
- Vprint_length = make_number (debug_print_length);
- if (debug_print_level > 0)
- Vprint_level = make_number (debug_print_level);
- print_internal (debug_print_obj, Qexternal_debugging_output, 1);
- stderr_out ("\n");
- fflush (stderr);
- Vinhibit_quit = old_inhibit_quit;
- Vprint_level = old_print_level;
- Vprint_length = old_print_length;
- print_depth = old_print_depth;
- print_readably = old_print_readably;
- print_unbuffered--;
- UNGCPRO;
- }
-
- /* Debugging kludge -- unbuffered */
- void debug_backtrace (void);
- void
- debug_backtrace (void)
- {
- /* This function can GC */
- int old_print_readably = print_readably;
- int old_print_depth = print_depth;
- Lisp_Object old_print_length = Vprint_length;
- Lisp_Object old_print_level = Vprint_level;
- Lisp_Object old_inhibit_quit = Vinhibit_quit;
- struct gcpro gcpro1, gcpro2, gcpro3;
- GCPRO3 (old_print_level, old_print_length, old_inhibit_quit);
-
- if (gc_in_progress)
- stderr_out ("** gc-in-progress! Bad idea to print anything! **\n");
-
- print_depth = 0;
- print_readably = 0;
- print_unbuffered++;
- /* Could use unwind-protect, but why bother? */
- if (debug_print_length > 0)
- Vprint_length = make_number (debug_print_length);
- if (debug_print_level > 0)
- Vprint_level = make_number (debug_print_level);
- Fbacktrace (Qexternal_debugging_output, Qt);
- stderr_out ("\n");
- fflush (stderr);
- Vinhibit_quit = old_inhibit_quit;
- Vprint_level = old_print_level;
- Vprint_length = old_print_length;
- print_depth = old_print_depth;
- print_readably = old_print_readably;
- print_unbuffered--;
- UNGCPRO;
- }
-
- #endif /* debugging kludge */
-
-
- void
- syms_of_print (void)
- {
- defsymbol (&Qprint_escape_newlines, "print-escape-newlines");
- defsymbol (&Qprint_readably, "print-readably");
-
- defsymbol (&Qstandard_output, "standard-output");
-
- #ifdef LISP_FLOAT_TYPE
- defsymbol (&Qfloat_output_format, "float-output-format");
- #endif
-
- defsymbol (&Qprint_length, "print-length");
-
- defsymbol (&Qprint_string_length, "print-string-length");
- defsubr (&Sprin1);
- defsubr (&Sprin1_to_string);
- defsubr (&Sprinc);
- defsubr (&Sprint);
- defsubr (&Sterpri);
- defsubr (&Swrite_char);
- defsubr (&Salternate_debugging_output);
- defsymbol (&Qalternate_debugging_output, "alternate-debugging-output");
- defsubr (&Sexternal_debugging_output);
- defsubr (&Sopen_termscript);
- defsymbol (&Qexternal_debugging_output, "external-debugging-output");
- #ifndef standalone
- defsubr (&Swith_output_to_temp_buffer);
- #endif /* not standalone */
- }
-
- void
- vars_of_print (void)
- {
- alternate_do_pointer = 0;
-
- DEFVAR_LISP ("standard-output", &Vstandard_output,
- "Output stream `print' uses by default for outputting a character.\n\
- This may be any function of one argument.\n\
- It may also be a buffer (output is inserted before point)\n\
- or a marker (output is inserted and the marker is advanced)\n\
- or the symbol t (output appears in the minibuffer line).");
- Vstandard_output = Qt;
-
- #ifdef LISP_FLOAT_TYPE
- DEFVAR_LISP ("float-output-format", &Vfloat_output_format,
- "The format descriptor string that lisp uses to print floats.\n\
- This is a %-spec like those accepted by `printf' in C,\n\
- but with some restrictions. It must start with the two characters `%.'.\n\
- After that comes an integer precision specification,\n\
- and then a letter which controls the format.\n\
- The letters allowed are `e', `f' and `g'.\n\
- Use `e' for exponential notation \"DIG.DIGITSeEXPT\"\n\
- Use `f' for decimal point notation \"DIGITS.DIGITS\".\n\
- Use `g' to choose the shorter of those two formats for the number at hand.\n\
- The precision in any of these cases is the number of digits following\n\
- the decimal point. With `f', a precision of 0 means to omit the\n\
- decimal point. 0 is not allowed with `f' or `g'.\n\n\
- A value of nil means to use `%.16g'.\n\
- \n\
- Regardless of the value of `float-output-format', a floating point number\n\
- will never be printed in such a way that it is ambiguous with an integer;\n\
- that is, a floating-point number will always be printed with a decimal\n\
- point and/or an exponent, even if the digits following the decimal point\n\
- are all zero. This is to preserve read-equivalence.");
- Vfloat_output_format = Qnil;
- #endif /* LISP_FLOAT_TYPE */
-
- DEFVAR_LISP ("print-length", &Vprint_length,
- "Maximum length of list or vector to print before abbreviating.\n\
- A value of nil means no limit.");
- Vprint_length = Qnil;
-
- DEFVAR_LISP ("print-string-length", &Vprint_string_length,
- "Maximum length of string to print before abbreviating.\n\
- A value of nil means no limit.");
- Vprint_string_length = Qnil;
-
- DEFVAR_LISP ("print-level", &Vprint_level,
- "Maximum depth of list nesting to print before abbreviating.\n\
- A value of nil means no limit.");
- Vprint_level = Qnil;
-
- DEFVAR_BOOL ("print-escape-newlines", &print_escape_newlines,
- "Non-nil means print newlines in strings as backslash-n.");
- print_escape_newlines = 0;
-
- DEFVAR_BOOL ("print-readably", &print_readably,
- "If non-nil, then all objects will be printed in a readable form.\n\
- If an object has no readable representation, then an error is signalled.\n\
- When print-readably is true, compiled-function objects will be written in\n\
- #[...] form instead of in #<byte-code [...]> form, and two-element lists\n\
- of the form (quote object) will be written as the equivalent 'object.\n\
- Do not SET this variable; bind it instead.");
- print_readably = 0;
-
- DEFVAR_BOOL ("print-gensym", &print_gensym,
- "If non-nil, then uninterned symbols will be printed specially.\n\
- Uninterned symbols are those which are not present in `obarray', that is,\n\
- those which were made with `make-symbol' or by calling `intern' with a\n\
- second argument.\n\
- \n\
- When print-gensym is true, such symbols will be preceeded by \"#:\", which\n\
- causes the reader to create a new symbol instead of interning and returning\n\
- an existing one. Beware: the #: syntax creates a new symbol each time it is\n\
- seen, so if you print an object which contains two pointers to the same\n\
- uninterned symbol, `read' will not duplicate that structure.\n\
- \n\
- Also, since emacs has no real notion of packages, there is no way for the\n\
- printer to distinguish between symbols interned in no obarray, and symbols\n\
- interned in an alternate obarray.");
- print_gensym = 0;
-
- DEFVAR_LISP ("print-message-label", &Vprint_message_label,
- "Label for minibuffer messages created with `print'. This should\n\
- generally be bound with `let' rather than set. (See `display-message'.)");
- Vprint_message_label = Qprint;
-
- /* prin1_to_string_buffer initialized in init_buffer_once in buffer.c */
- staticpro (&Vprin1_to_string_buffer);
- }
-